<template>
  <section id="vizContainer" :class="{ fullscreen: isFullscreen }" @dblclick="toggleFullscreen">
    <div class="artifacts">
      <div v-if="selectedVisualizer" class="credits">
        <h3>{{ selectedVisualizer.name }}</h3>
        <p v-if="selectedVisualizer.credits" class="text-secondary">
          by {{ selectedVisualizer.credits.author }}
          <a :href="selectedVisualizer.credits.url" target="_blank">
            <Icon :icon="faUpRightFromSquare" />
          </a>
        </p>
      </div>

      <select v-model="selectedId">
        <option disabled value="-1">Pick a visualizer</option>
        <option v-for="v in visualizers" :key="v.id" :value="v.id">{{ v.name }}</option>
      </select>
    </div>
    <div ref="el" class="viz" />
  </section>
</template>

<script lang="ts" setup>
import { faUpRightFromSquare } from '@fortawesome/free-solid-svg-icons'
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { logger } from '@/utils'
import { preferenceStore as preferences, visualizerStore } from '@/stores'

const visualizers = visualizerStore.all
let destroyVisualizer: () => void

const el = ref<HTMLElement>()
const selectedId = ref<Visualizer['id']>()
const isFullscreen = ref(false)

const render = async (viz: Visualizer) => {
  if (!el.value) {
    await nextTick()
    await render(viz)
  }

  freeUp()

  try {
    destroyVisualizer = await viz.init(el.value!)
  } catch (e) {
    // in e.g., DOM testing, the call will fail due to the lack of proper API support
    logger.warn('Failed to initialize visualizer', e)
  }
}

const selectedVisualizer = ref<Visualizer>()

watch(selectedId, id => {
  preferences.visualizer = id
  selectedVisualizer.value = visualizerStore.getVisualizerById(id || 'default')!
  render(selectedVisualizer.value)
})

const toggleFullscreen = () => {
  isFullscreen.value ? document.exitFullscreen() : el.value?.requestFullscreen()
  isFullscreen.value = !isFullscreen.value
}

onMounted(() => {
  selectedId.value = preferences.visualizer || 'default'

  if (!visualizerStore.getVisualizerById(selectedId.value)) {
    selectedId.value = 'default'
  }
})

const freeUp = () => {
  destroyVisualizer?.()
  el.value && (el.value.innerHTML = '')
}

onBeforeUnmount(() => freeUp())
</script>

<style lang="scss">
#vizContainer {
  .viz {
    height: 100%;
    width: 100%;
    position: absolute;
    z-index: 0;

    canvas {
      transition: opacity 0.3s;
      height: 100%;
      width: 100%;
    }
  }

  .artifacts {
    position: absolute;
    z-index: 1;
    height: 100%;
    width: 100%;
    top: 0;
    left: 0;
    opacity: 0;
    padding: 24px;
    transition: opacity 0.3s ease-in-out;
  }

  &:hover {
    .artifacts {
      opacity: 1;
    }
  }

  .credits {
    padding: 14px 28px 14px 14px;
    background: rgba(0, 0, 0, .5);
    width: fit-content;
    position: absolute;
    bottom: 24px;

    h3 {
      font-size: 1.2rem;
      margin-bottom: .3rem;
    }

    a {
      margin-left: .5rem;
      display: inline-block;
      vertical-align: middle;
    }
  }

  select {
    position: absolute;
    bottom: 24px;
    right: 24px;
  }

  &.fullscreen {
    // :fullscreen pseudo support is kind of buggy, so we use a class instead.
    background: var(--color-bg-primary);

    .close {
      opacity: 0 !important;
    }
  }
}
</style>
